Skip to content

Add autonomous agents page under contract accounts - #2811

Open
Eras256 wants to merge 4 commits into
stellar:mainfrom
Eras256:docs/autonomous-agents
Open

Add autonomous agents page under contract accounts#2811
Eras256 wants to merge 4 commits into
stellar:mainfrom
Eras256:docs/autonomous-agents

Conversation

@Eras256

@Eras256 Eras256 commented Sep 1, 2026

Copy link
Copy Markdown

What

Adds a new page, docs/build/guides/contract-accounts/autonomous-agents.mdx, sitting alongside the existing Advanced contract account patterns page. No existing files touched.

Why

Advanced contract account patterns covers the individual guardrail primitives (spend limits, allow lists, policy signers, time rules, session keys, external policy contracts) — installed once, typically for a human session. An autonomous agent is a different caller: the same signing key stays live indefinitely and decides on its own when to act, so the restriction has to hold for as long as the agent keeps running, not just at setup.

This page covers two composable ways to bound an agent's authority (restricting the callee's own instruction set vs. restricting the caller's key via a smart account policy, and why you generally want both), plus three pitfalls that specifically only surface once the agent is actually operating rather than when the policy is installed:

  • Recording-mode simulation records require_auth calls as successful and never emulates authorization failures — testing a deny path requires actually submitting in enforcement mode, not reading a clean simulation.
  • A long-running loop has to re-read its own authority from chain every cycle; caching it means a revocation made mid-run does nothing until the process restarts.
  • Where an LLM's discretion should stop and hard-coded, unauthorable limits should begin, if a model is part of the agent's decision loop.

Closes with a short note on what a technically sound restriction does and doesn't resolve (the legal categorization question is separate from the technical one).

Notes

  • Every technical claim is cited against a live source: the exact rebalance() instruction set is quoted from DeFindex's current public repo (verified directly, not from memory — an instruction set some notes elsewhere describe as having dropped swap support, which is not what the current code shows); the simulation behavior is quoted verbatim from this site's own Transaction Simulation page; the Certora line matches this site's own OpenZeppelin Contracts page wording exactly ("is being completed", not "completed" — no Certora report exists in OpenZeppelin's own audits/ folder yet).
  • One example deployment is named once, descriptively (a testnet contract address, independently verifiable via Stellar Expert) — same treatment the sibling page already gives OpenZeppelin's and Crossmint's contracts in its own "Where to go next".
  • sidebar_position: 45, between Advanced contract account patterns (40) and Contract account examples (50).
  • pnpm check:mdx passes clean against the real .prettierrc.js.

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com

Covers bounding a long-running agent's authority with two composable
restriction layers (callee-side instruction-set design, key-side smart
account policy) and three runtime pitfalls that don't show up until the
agent is actually operating: simulation not verifying auth, stale cached
authority in a long-running loop, and where LLM discretion should stop
versus hard-coded limits.

Sits alongside the existing Advanced contract account patterns page,
which covers the design-time guardrail primitives this page composes
for a specifically autonomous, unattended caller.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings September 1, 2026 18:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds guidance for safely bounding autonomous agents using contract restrictions and smart-account policies.

Changes:

  • Documents layered authority restrictions.
  • Covers simulation, revocation, and model-safety pitfalls.
  • Links to relevant implementations and specifications.

Recommendation: NEEDS-CHANGES — Correct the overstated security and revocation claims, and use relative links for internal pages.

Suppressed comments (1)

docs/build/guides/contract-accounts/autonomous-agents.mdx:40

  • This is an in-repository docs target and should be relative so it resolves in local and versioned previews.
- [OpenZeppelin Smart Accounts](https://developers.stellar.org/docs/tools/openzeppelin-contracts) — context rules, signers, and policies, audited by OpenZeppelin's security team, with formal verification by Certora in progress.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
The composed-layers paragraph implied the key-wrapping (smart account)
layer was operating alongside the callee-side restriction. It isn't yet:
the deployed contract's context_rules are confirmed correct by reading
them on-chain, but nothing has authorized a real signed transaction
through it. Only the callee-side restriction (DeFindex's Invest/Unwind)
has a track record of real signed calls. Correcting before that
distinction gets cited as settled.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 1, 2026 19:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 2 comments.

Suppressed comments (3)

Previously missed (1) — in code that hasn't changed since the last review.

docs/build/guides/contract-accounts/autonomous-agents.mdx:17

  • CallContract(vault) scopes the credential to an address, not a function, and DeFindex also exposes withdrawal and administrative entry points. The final sentence therefore overstates what the two described layers guarantee: the bound comes from assigning this account only the RebalanceManager role. State that dependency explicitly rather than claiming the whole contract can only return funds to itself.
Neither layer is sufficient alone for an unattended agent. Restrict only the callee, and a leaked key can still authorize anything the callee's own logic happens to allow — a swap at bad slippage, say, if the callee supports swaps at all. Restrict only the key, and you're trusting that the callee's logic never grows a footgun later. Composed, an agent's key can only reach one contract, and that contract can't move funds anywhere but back into itself.

docs/build/guides/contract-accounts/autonomous-agents.mdx:42

  • Links from docs/** to another page in this repository must be relative; the hard-coded published-site URL can also break preview/versioned builds. Point this link at the local MDX page.
- [OpenZeppelin Smart Accounts](https://developers.stellar.org/docs/tools/openzeppelin-contracts) — context rules, signers, and policies, audited by OpenZeppelin's security team, with formal verification by Certora in progress.

docs/build/guides/contract-accounts/autonomous-agents.mdx:29

  • Revocation does not become ineffective when the process caches an earlier permission read: the contract evaluates its current on-chain role and authorization state for every submitted call, so a revoked agent's later transaction fails. Re-reading each cycle is still useful to stop constructing or submitting doomed transactions, but it is not what enforces revocation. Please correct this security behavior.
A human signer revokes access once, and the session ends there. A long-running agent process keeps looping regardless of what changed underneath it, so if it caches "am I still authorized" from the start of the process, a revocation made ten minutes into a multi-day run does nothing until the process restarts. Read the current role or permission state from chain at the top of every cycle, not once at boot.

Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
Confirmed empirically (needsNonInvokerSigningBy(), raw simulation auth
entries, both authMode values) that a Signer::Delegated's own signing
requirement never surfaces via the SDK's standard discovery flow — full
detail and repro in OpenZeppelin/stellar-contracts#863. Framed with the
same precision as that issue: what's empirically confirmed vs. what's
inferred about recording mode's internal behavior, not independently
verified against the host implementation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 1, 2026 20:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.

Suppressed comments (3)

Previously missed (1) — in code that hasn't changed since the last review.

docs/build/guides/contract-accounts/autonomous-agents.mdx:17

  • This overstates the callee-side guarantee. DeFindex investments send assets into strategy contracts, and swaps transfer input to a pair; the verified property is that proceeds cannot be directed to an arbitrary recipient, not that funds never move anywhere except back into the vault. Narrow the conclusion to the actual destination restriction.
Neither layer is sufficient alone for an unattended agent. Restrict only the callee, and a leaked key can still authorize anything the callee's own logic happens to allow — a swap at bad slippage, say, if the callee supports swaps at all. Restrict only the key, and you're trusting that the callee's logic never grows a footgun later. Composed, an agent's key can only reach one contract, and that contract can't move funds anywhere but back into itself.

docs/build/guides/contract-accounts/autonomous-agents.mdx:25

  • This conflates two different operations: enforce is a simulateTransaction authorization mode, while an on-chain submission has no “enforcement mode.” The internal link also needs to be relative. Distinguish enforcement-mode simulation from actual transaction submission so readers can implement the deny-path test correctly.
[Recording-mode simulation](https://developers.stellar.org/docs/learn/fundamentals/contract-development/contract-interactions/transaction-simulation#recording-mode) records every `require_auth` call as successful, and "never emulates authorization failures... failing authorization is always an 'exceptional' situation." That's the right behavior for building a transaction to sign, and the wrong tool for testing that a restriction actually holds. A policy that looks correctly restrictive under simulation can still pass simulation for an action it should deny, because simulation was never checking the signature in the first place. To test the deny path, submit the transaction in enforcement mode and confirm it actually fails on-chain — don't infer it from a clean simulation.

docs/build/guides/contract-accounts/autonomous-agents.mdx:46

  • Docs links to pages in this repository must be relative. Point this item at the local MDX source rather than the published-site URL.
- [OpenZeppelin Smart Accounts](https://developers.stellar.org/docs/tools/openzeppelin-contracts) — context rules, signers, and policies, audited by OpenZeppelin's security team, with formal verification by Certora in progress.

Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
Comment thread docs/build/guides/contract-accounts/autonomous-agents.mdx Outdated
…al ones

Verified each of Copilot's six review points against real source
before responding, per the standing discipline:

- DeFindex rebalance(): Copilot was right. The router's own source
  shows a swap's input leg transfers to the trading pool mid-execution,
  not only ever back to the vault. Narrowed the claim.
- Nirium Invest/Unwind evidence: Copilot was wrong (or working from a
  stale source) — there are two of each, not one Invest and zero
  Unwind. Verified b7bf6d70... (Unwind) directly against Horizon before
  citing it; both hashes now linked explicitly instead of an unbacked
  claim.
- Hardcoded published-site URLs (3 instances): fixed to relative links,
  verified with the repo's own scripts/check-relative-links.sh.
- Caching/revocation: Copilot was right — __check_auth re-reads current
  rules from chain every check, so an on-chain revocation is effective
  regardless of what a process cached. Reframed: the real cost of
  caching is wasted cycles and delayed self-awareness, not a security
  bypass.
- "Enforcement mode": fixed to name the real authMode values (enforce/
  record/record_allow_nonroot) and be precise that a real submission,
  not a special mode, is what actually enforces auth.
- AuthMode count/API usage: Copilot's core technical point (three modes,
  not two) is correct per the real CHANGELOG, even though the specific
  file path it cited doesn't exist in this repo. Checking this surfaced
  a real methodological gap in the linked issue's own multi-mode claim
  (OpenZeppelin/stellar-contracts#863) — softened this page's citation
  to what's independently confirmed, added a real on-chain settlement
  of the delegated-signer case as stronger evidence.

pnpm exec prettier -c and scripts/check-relative-links.sh --range both
pass clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 3, 2026 15:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

docs/build/guides/contract-accounts/autonomous-agents.mdx:25

  • A deny path does not require an on-chain submission. This repository's Transaction Simulation page says enforcing mode executes __check_auth and is effectively equivalent to on-chain execution, while the signing guide explicitly recommends enforcing-mode simulation to catch authorization errors without paying fees. Instruct readers to provide the attempted transaction's auth entries/signatures and confirm that an enforcing-mode simulation fails; submission is optional.
[Recording-mode simulation](../../../learn/fundamentals/contract-development/contract-interactions/transaction-simulation.mdx#recording-mode) records every `require_auth` call as successful, and "never emulates authorization failures... failing authorization is always an 'exceptional' situation." That's the right behavior for building a transaction to sign, and the wrong tool for testing that a restriction actually holds. A policy that looks correctly restrictive under simulation can still pass simulation for an action it should deny, because simulation was never checking the signature in the first place. `simulateTransaction` takes an `authMode` of `enforce`, `record`, or `record_allow_nonroot` — to test the deny path, actually submit the transaction (a real submission always enforces authorization, `authMode` or not) and confirm it fails on-chain. Don't infer a deny path from a clean recording-mode simulation.

docs/build/guides/contract-accounts/autonomous-agents.mdx:33

  • The chain cannot reject an attempt to sign: signing happens locally with the agent's private key and does not consult __check_auth. Revocation is enforced when the transaction is simulated in enforcing mode or submitted, so saying the next transaction the agent “tries to sign” is rejected misstates the security boundary.
An on-chain revocation is effective the moment it lands, regardless of what any process has cached: `__check_auth` re-reads the account's current rules from chain on every check, so the very next transaction the agent tries to sign is rejected whether or not its own process noticed anything changed. What caching actually costs you is time and signal, not security. A long-running agent that only reads "am I still authorized" once at boot keeps looping anyway, spending cycles building and submitting transactions that fail on-chain one after another, instead of noticing the moment its authority changed and stopping or alerting. Read the current role or permission state from chain at the top of every cycle — not to keep the revocation itself effective, but so the agent finds out it's been cut off immediately, not after a string of failed submissions.


**Restrict the key.** The complementary layer is scoping the caller's own credential, using the account-abstraction primitives already covered on this page and the [previous one](./advanced-patterns.mdx): a smart account whose only context rule is `CallContract(the one vault you want)`, with no default/catch-all rule installed. The absence of a fallback rule is what does the work — a context that isn't covered by an explicit rule has no rule that authorizes it.

Neither layer is sufficient alone for an unattended agent. Restrict only the callee, and a leaked key can still authorize anything the callee's own logic happens to allow — a swap at bad slippage, say, if the callee supports swaps at all. Restrict only the key, and you're trusting that the callee's logic never grows a footgun later. Composed, an agent's key can only reach one contract, and that contract can't move funds anywhere but back into itself.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants